home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Magazine / Online / QMail / source / qmail-inject.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-02  |  18.5 KB  |  741 lines

  1. #include "sig.h"
  2. #include "substdio.h"
  3. #include "stralloc.h"
  4. #include "subfd.h"
  5. #include "sgetopt.h"
  6. #include "getln.h"
  7. #include "alloc.h"
  8. #include "str.h"
  9. #include "fmt.h"
  10. #include "hfield.h"
  11. #include "token822.h"
  12. #include "control.h"
  13. #include "env.h"
  14. #include "gen_alloc.h"
  15. #include "gen_allocdefs.h"
  16. #include "error.h"
  17. #include "qmail.h"
  18. #include "now.h"
  19. #include "exit.h"
  20. #include "quote.h"
  21. #include "headerbody.h"
  22. #include "auto_qmail.h"
  23. #include "newfield.h"
  24. #define puts stdio_puts
  25. #include <pwd.h>
  26. #undef puts
  27.  
  28. #define LINELEN 80
  29.  
  30. datetime_sec starttime;
  31.  
  32. char *qmopts;
  33. int flagdeletesender = 0;
  34. int flagdeletefrom = 0;
  35. int flagdeletemessid = 0;
  36. int flagnamecomment = 0;
  37. int flaghackmess = 0;
  38. int flaghackrecip = 0;
  39. char *mailhost;
  40. char *mailuser;
  41. int mailusertokentype;
  42. char *mailrhost;
  43. char *mailruser;
  44.  
  45. stralloc control_idhost = {0};
  46. stralloc control_defaultdomain = {0};
  47. stralloc control_defaulthost = {0};
  48. stralloc control_plusdomain = {0};
  49.  
  50. stralloc sender = {0};
  51. stralloc envsbuf = {0};
  52. token822_alloc envs = {0};
  53. int flagrh;
  54.  
  55. int flagqueue;
  56. struct qmail qqt;
  57.  
  58. void put(s,len) char *s; int len;
  59. { if (flagqueue) qmail_put(&qqt,s,len); else substdio_put(subfdout,s,len); }
  60. void puts(s) char *s; { put(s,str_len(s)); }
  61.  
  62. void perm() { _exit(100); }
  63. void temp() { _exit(111); }
  64. void die_nomem() {
  65.  substdio_putsflush(subfderr,"qmail-inject: fatal: out of memory\n"); temp(); }
  66. void die_invalid(sa) stralloc *sa; {
  67.  substdio_putsflush(subfderr,"qmail-inject: fatal: invalid header field: ");
  68.  substdio_putflush(subfderr,sa->s,sa->len); perm(); }
  69. void die_exec() {
  70.  substdio_putsflush(subfderr,"qmail-inject: fatal: unable to exec qmail-queue\n"); temp(); }
  71. void die_qqt() {
  72.  substdio_putsflush(subfderr,"qmail-inject: fatal: unable to run qmail-queue\n"); temp(); }
  73. void die_chdir() {
  74.  substdio_putsflush(subfderr,"qmail-inject: fatal: internal bug\n"); temp(); }
  75. void die_bug() {
  76.  substdio_putsflush(subfderr,"qmail-inject: fatal: internal bug\n"); temp(); }
  77. void die_read() {
  78.  if (errno == error_nomem) die_nomem();
  79.  substdio_putsflush(subfderr,"qmail-inject: fatal: read error\n"); temp(); }
  80. void doordie(sa,r) stralloc *sa; int r; {
  81.  if (r == 1) return; if (r == -1) die_nomem();
  82.  substdio_putsflush(subfderr,"qmail-inject: fatal: unable to parse this line:\n");
  83.  substdio_putflush(subfderr,sa->s,sa->len); perm(); }
  84.  
  85. void die_comm() {
  86.  substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue lost communications link\n"); temp(); }
  87. void die_qq() {
  88.  substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue died\n"); temp(); }
  89. void die_qqwrite() {
  90.  substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue unable to write message to disk; disk full?\n"); temp(); }
  91. void die_qqsig() {
  92.  substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue was killed\n"); temp(); }
  93. void die_qqtimeout() {
  94.  substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue timed out\n"); temp(); }
  95. void die_qqtoolong() {
  96.  substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue unhappy with long addresses\n"); perm(); }
  97.  
  98. GEN_ALLOC_typedef(saa,stralloc,sa,len,a)
  99. GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus)
  100.  
  101. static stralloc sauninit = {0};
  102.  
  103. saa savedh = {0};
  104. saa hrlist = {0};
  105. saa hrrlist = {0};
  106. saa reciplist = {0};
  107. int flagresent;
  108.  
  109. void exitnicely()
  110. {
  111.  if (!flagqueue) substdio_flush(subfdout);
  112.  
  113.  if (flagqueue)
  114.   {
  115.    int i;
  116.  
  117.    if (!stralloc_0(&sender)) die_nomem();
  118.    qmail_from(&qqt,sender.s);
  119.  
  120.    for (i = 0;i < reciplist.len;++i)
  121.     {
  122.      if (!stralloc_0(&reciplist.sa[i])) die_nomem();
  123.      qmail_to(&qqt,reciplist.sa[i].s);
  124.     }
  125.    if (flagrh)
  126.      if (flagresent)
  127.        for (i = 0;i < hrrlist.len;++i)
  128.     {
  129.          if (!stralloc_0(&hrrlist.sa[i])) die_nomem();
  130.      qmail_to(&qqt,hrrlist.sa[i].s);
  131.     }
  132.      else
  133.        for (i = 0;i < hrlist.len;++i)
  134.     {
  135.          if (!stralloc_0(&hrlist.sa[i])) die_nomem();
  136.      qmail_to(&qqt,hrlist.sa[i].s);
  137.     }
  138.  
  139.    switch(qmail_close(&qqt))
  140.     {
  141.      case 0: break;
  142.      case QMAIL_CRASHED: die_qqsig();
  143.      case QMAIL_USAGE: case QMAIL_BUG: die_bug();
  144.      case QMAIL_EXECSOFT: die_exec();
  145.      case QMAIL_NOMEM: die_nomem();
  146.      case QMAIL_READ: die_comm();
  147.      case QMAIL_WRITE: die_qqwrite();
  148.      case QMAIL_TOOLONG: die_qqtoolong();
  149.      case QMAIL_TIMEOUT: die_qqtimeout();
  150.      default: die_qq();
  151.     }
  152.   }
  153.  
  154.  _exit(0);
  155. }
  156.  
  157. void savedh_append(h)
  158. stralloc *h;
  159. {
  160.  if (!saa_readyplus(&savedh,1)) die_nomem();
  161.  savedh.sa[savedh.len] = sauninit;
  162.  if (!stralloc_copy(savedh.sa + savedh.len,h)) die_nomem();
  163.  ++savedh.len;
  164. }
  165.  
  166. void savedh_print()
  167. {
  168.  int i;
  169.  
  170.  for (i = 0;i < savedh.len;++i)
  171.    put(savedh.sa[i].s,savedh.sa[i].len);
  172. }
  173.  
  174. stralloc defaultdomainbuf = {0};
  175. token822_alloc defaultdomain = {0};
  176. stralloc defaulthostbuf = {0};
  177. token822_alloc defaulthost = {0};
  178. stralloc plusdomainbuf = {0};
  179. token822_alloc plusdomain = {0};
  180.  
  181. void rwroute(addr)
  182. token822_alloc *addr;
  183. {
  184.  if (addr->t[addr->len - 1].type == TOKEN822_AT)
  185.    while (addr->len)
  186.      if (addr->t[--addr->len].type == TOKEN822_COLON)
  187.        return;
  188. }
  189.  
  190. void rwextraat(addr)
  191. token822_alloc *addr;
  192. {
  193.  int i;
  194.  if (addr->t[0].type == TOKEN822_AT)
  195.   {
  196.    --addr->len;
  197.    for (i = 0;i < addr->len;++i)
  198.      addr->t[i] = addr->t[i + 1];
  199.   }
  200. }
  201.  
  202. void rwextradot(addr)
  203. token822_alloc *addr;
  204. {
  205.  int i;
  206.  if (addr->t[0].type == TOKEN822_DOT)
  207.   {
  208.    --addr->len;
  209.    for (i = 0;i < addr->len;++i)
  210.      addr->t[i] = addr->t[i + 1];
  211.   }
  212. }
  213.  
  214. void rwnoat(addr)
  215. token822_alloc *addr;
  216. {
  217.  int i;
  218.  int shift;
  219.  
  220.  for (i = 0;i < addr->len;++i)
  221.    if (addr->t[i].type == TOKEN822_AT)
  222.      return;
  223.  shift = defaulthost.len;
  224.  if (!token822_readyplus(addr,shift)) die_nomem();
  225.  for (i = addr->len - 1;i >= 0;--i)
  226.    addr->t[i + shift] = addr->t[i];
  227.  addr->len += shift;
  228.  for (i = 0;i < shift;++i)
  229.    addr->t[i] = defaulthost.t[shift - 1 - i];
  230. }
  231.  
  232. void rwnodot(addr)
  233. token822_alloc *addr;
  234. {
  235.  int i;
  236.  int shift;
  237.  for (i = 0;i < addr->len;++i)
  238.   {
  239.    if (addr->t[i].type == TOKEN822_DOT)
  240.      return;
  241.    if (addr->t[i].type == TOKEN822_AT)
  242.      break;
  243.   }
  244.  for (i = 0;i < addr->len;++i)
  245.   {
  246.    if (addr->t[i].type == TOKEN822_LITERAL)
  247.      return;
  248.    if (addr->t[i].type == TOKEN822_AT)
  249.      break;
  250.   }
  251.  shift = defaultdomain.len;
  252.  if (!token822_readyplus(addr,shift)) die_nomem();
  253.  for (i = addr->len - 1;i >= 0;--i)
  254.    addr->t[i + shift] = addr->t[i];
  255.  addr->len += shift;
  256.  for (i = 0;i < shift;++i)
  257.    addr->t[i] = defaultdomain.t[shift - 1 - i];
  258. }
  259.  
  260. void rwplus(addr)
  261. token822_alloc *addr;
  262. {
  263.  int i;
  264.  int shift;
  265.  
  266.  if (addr->t[0].type != TOKEN822_ATOM) return;
  267.  if (!addr->t[0].slen) return;
  268.  if (addr->t[0].s[addr->t[0].slen - 1] != '+') return;
  269.  
  270.  --addr->t[0].slen; /* remove + */
  271.  
  272.  shift = plusdomain.len;
  273.  if (!token822_readyplus(addr,shift)) die_nomem();
  274.  for (i = addr->len - 1;i >= 0;--i)
  275.    addr->t[i + shift] = addr->t[i];
  276.  addr->len += shift;
  277.  for (i = 0;i < shift;++i)
  278.    addr->t[i] = plusdomain.t[shift - 1 - i];
  279. }
  280.  
  281. void rwgeneric(addr)
  282. token822_alloc *addr;
  283. {
  284.  if (!addr->len) return; /* don't rewrite <> */
  285.  if (addr->len >= 2)
  286.    if (addr->t[1].type == TOKEN822_AT)
  287.      if (addr->t[0].type == TOKEN822_LITERAL)
  288.        if (!addr->t[0].slen) /* don't rewrite <foo@[]> */
  289.      return;
  290.  rwroute(addr);
  291.  if (!addr->len) return; /* <@foo:> -> <> */
  292.  rwextradot(addr);
  293.  if (!addr->len) return; /* <.> -> <> */
  294.  rwextraat(addr);
  295.  if (!addr->len) return; /* <@> -> <> */
  296.  rwnoat(addr);
  297.  rwplus(addr);
  298.  rwnodot(addr);
  299. }
  300.  
  301. int setreturn(addr)
  302. token822_alloc *addr;
  303. {
  304.  if (!sender.s)
  305.   {
  306.    token822_reverse(addr);
  307.    if (token822_unquote(&sender,addr) != 1) die_nomem();
  308.    if (flaghackrecip)
  309.      if (!stralloc_cats(&sender,"-@[]")) die_nomem();
  310.    token822_reverse(addr);
  311.   }
  312.  return 1;
  313. }
  314.  
  315. int rwreturn(addr)
  316. token822_alloc *addr;
  317. {
  318.  rwgeneric(addr);
  319.  setreturn(addr);
  320.  return 1;
  321. }
  322.  
  323. int rwsender(addr)
  324. token822_alloc *addr;
  325. {
  326.  rwgeneric(addr);
  327.  return 1;
  328. }
  329.  
  330. void rwrecip(addr,xl)
  331. token822_alloc *addr;
  332. saa *xl;
  333. {
  334.  rwgeneric(addr);
  335.  token822_reverse(addr);
  336.  if (!saa_readyplus(xl,1)) die_nomem();
  337.  xl->sa[xl->len] = sauninit;
  338.  if (token822_unquote(&xl->sa[xl->len],addr) != 1) die_nomem();
  339.  ++xl->len;
  340.  token822_reverse(addr);
  341. }
  342.  
  343. int rwhrr(addr) token822_alloc *addr;
  344. { rwrecip(addr,&hrrlist); return 1; }
  345. int rwhr(addr) token822_alloc *addr;
  346. { rwrecip(addr,&hrlist); return 1; }
  347.  
  348. int htypeseen[H_NUM];
  349. stralloc hfbuf = {0};
  350. token822_alloc hfin = {0};
  351. token822_alloc hfrewrite = {0};
  352. token822_alloc hfaddr = {0};
  353.  
  354. void doheaderfield(h)
  355. stralloc *h;
  356. {
  357.  int htype;
  358.  int flagrewrite;
  359.  int flagrecip;
  360.  int flagrr;
  361.  
  362.  htype = hfield_known(h->s,h->len);
  363.  if (flagdeletefrom) if (htype == H_FROM) return;
  364.  if (flagdeletemessid) if (htype == H_MESSAGEID) return;
  365.  if (flagdeletesender) if (htype == H_RETURNPATH) return;
  366.  
  367.  if (htype)
  368.    htypeseen[htype] = 1;
  369.  else
  370.    if (!hfield_valid(h->s,h->len))
  371.      die_invalid(h);
  372.  
  373.  flagrewrite = 0;
  374.  flagrecip = 0;
  375.  flagrr = 0;
  376.  switch(htype)
  377.   {
  378.    case H_R_TO: case H_R_CC: case H_R_BCC:
  379.      flagrr = 1;
  380.    case H_TO: case H_CC: case H_BCC: case H_APPARENTLYTO:
  381.      flagrecip = 1;
  382.    case H_SENDER: case H_FROM: case H_REPLYTO:
  383.    case H_RETURNRECEIPTTO: case H_ERRORSTO: case H_RETURNPATH:
  384.    case H_R_SENDER: case H_R_FROM: case H_R_REPLYTO:
  385.      flagrewrite = 1;
  386.      break;
  387.   }
  388.  
  389.  if (flagrewrite)
  390.   {
  391.    doordie(h,token822_parse(&hfin,h,&hfbuf));
  392.    doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,(htype == H_RETURNPATH) ? rwreturn : (flagrecip ? (flagrr ? rwhrr : rwhr) : rwsender)));
  393.    if (token822_unparse(h,&hfrewrite,LINELEN) != 1)
  394.      die_nomem();
  395.   }
  396.  
  397.  if (htype == H_BCC) return;
  398.  if (htype == H_R_BCC) return;
  399.  if (htype == H_RETURNPATH) return;
  400.  if (htype == H_CONTENTLENGTH) return; /* some things are just too stupid */
  401.  savedh_append(h);
  402. }
  403.  
  404. void dobody(h)
  405. stralloc *h;
  406. {
  407.  put(h->s,h->len);
  408. }
  409.  
  410. stralloc torecip = {0};
  411. token822_alloc tr = {0};
  412.  
  413. void dorecip(s)
  414. char *s;
  415. {
  416.  if (!quote2(&torecip,s)) die_nomem();
  417.  switch(token822_parse(&tr,&torecip,&hfbuf))
  418.   {
  419.    case -1: die_nomem();
  420.    case 0:
  421.      substdio_puts(subfderr,"qmail-inject: fatal: unable to parse address: ");
  422.      substdio_puts(subfderr,s);
  423.      substdio_putsflush(subfderr,"\n");
  424.      perm();
  425.   }
  426.  token822_reverse(&tr);
  427.  rwrecip(&tr,&reciplist);
  428. }
  429.  
  430. stralloc defaultfrom = {0};
  431. token822_alloc df = {0};
  432.  
  433. void defaultfrommake()
  434. {
  435.  char *fullname;
  436.  fullname = env_get("QMAILNAME");
  437.  if (!fullname) fullname = env_get("MAILNAME");
  438.  if (!fullname) fullname = env_get("NAME");
  439.  if (!token822_ready(&df,20)) die_nomem();
  440.  df.len = 0;
  441.  df.t[df.len].type = TOKEN822_ATOM;
  442.  df.t[df.len].s = "From";
  443.  df.t[df.len].slen = 4;
  444.  ++df.len;
  445.  df.t[df.len].type = TOKEN822_COLON;
  446.  ++df.len;
  447.  if (fullname && !flagnamecomment)
  448.   {
  449.    df.t[df.len].type = TOKEN822_QUOTE;
  450.    df.t[df.len].s = fullname;
  451.    df.t[df.len].slen = str_len(fullname);
  452.    ++df.len;
  453.    df.t[df.len].type = TOKEN822_LEFT;
  454.    ++df.len;
  455.   }
  456.  df.t[df.len].type = mailusertokentype;
  457.  df.t[df.len].s = mailuser;
  458.  df.t[df.len].slen = str_len(mailuser);
  459.  ++df.len;
  460.  if (mailhost)
  461.   {
  462.    df.t[df.len].type = TOKEN822_AT;
  463.    ++df.len;
  464.    df.t[df.len].type = TOKEN822_ATOM;
  465.    df.t[df.len].s = mailhost;
  466.    df.t[df.len].slen = str_len(mailhost);
  467.    ++df.len;
  468.   }
  469.  if (fullname && !flagnamecomment)
  470.   {
  471.    df.t[df.len].type = TOKEN822_RIGHT;
  472.    ++df.len;
  473.   }
  474.  if (fullname && flagnamecomment)
  475.   {
  476.    df.t[df.len].type = TOKEN822_COMMENT;
  477.    df.t[df.len].s = fullname;
  478.    df.t[df.len].slen = str_len(fullname);
  479.    ++df.len;
  480.   }
  481.  if (token822_unparse(&defaultfrom,&df,LINELEN) != 1) die_nomem();
  482.  doordie(&defaultfrom,token822_parse(&df,&defaultfrom,&hfbuf));
  483.  doordie(&defaultfrom,token822_addrlist(&hfrewrite,&hfaddr,&df,rwsender));
  484.  if (token822_unparse(&defaultfrom,&hfrewrite,LINELEN) != 1) die_nomem();
  485. }
  486.  
  487. stralloc defaultreturnpath = {0};
  488. token822_alloc drp = {0};
  489. stralloc hackedruser = {0};
  490. char strnum[FMT_ULONG];
  491.  
  492. void dodefaultreturnpath()
  493. {
  494.  if (!stralloc_copys(&hackedruser,mailruser)) die_nomem();
  495.  if (flaghackmess)
  496.   {
  497.    if (!stralloc_cats(&hackedruser,"-")) die_nomem();
  498.    if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long) starttime))) die_nomem();
  499.    if (!stralloc_cats(&hackedruser,".")) die_nomem();
  500.    if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
  501.   }
  502.  if (flaghackrecip)
  503.    if (!stralloc_cats(&hackedruser,"-")) die_nomem();
  504.  if (!token822_ready(&drp,10)) die_nomem();
  505.  drp.len = 0;
  506.  drp.t[drp.len].type = TOKEN822_ATOM;
  507.  drp.t[drp.len].s = "Return-Path";
  508.  drp.t[drp.len].slen = 11;
  509.  ++drp.len;
  510.  drp.t[drp.len].type = TOKEN822_COLON;
  511.  ++drp.len;
  512.  drp.t[drp.len].type = TOKEN822_QUOTE;
  513.  drp.t[drp.len].s = hackedruser.s;
  514.  drp.t[drp.len].slen = hackedruser.len;
  515.  ++drp.len;
  516.  if (mailrhost)
  517.   {
  518.    drp.t[drp.len].type = TOKEN822_AT;
  519.    ++drp.len;
  520.    drp.t[drp.len].type = TOKEN822_ATOM;
  521.    drp.t[drp.len].s = mailrhost;
  522.    drp.t[drp.len].slen = str_len(mailrhost);
  523.    ++drp.len;
  524.   }
  525.  if (token822_unparse(&defaultreturnpath,&drp,LINELEN) != 1) die_nomem();
  526.  doordie(&defaultreturnpath,token822_parse(&drp,&defaultreturnpath,&hfbuf));
  527.  doordie(&defaultreturnpath
  528.    ,token822_addrlist(&hfrewrite,&hfaddr,&drp,rwreturn));
  529.  if (token822_unparse(&defaultreturnpath,&hfrewrite,LINELEN) != 1) die_nomem();
  530. }
  531.  
  532. void finishheader()
  533. {
  534.  flagresent =
  535.    htypeseen[H_R_SENDER] || htypeseen[H_R_FROM] || htypeseen[H_R_REPLYTO]
  536.    || htypeseen[H_R_TO] || htypeseen[H_R_CC] || htypeseen[H_R_BCC]
  537.    || htypeseen[H_R_DATE] || htypeseen[H_R_MESSAGEID];
  538.  
  539.  if (!sender.s)
  540.    dodefaultreturnpath();
  541.  
  542.  if (!flagqueue)
  543.   {
  544.    static stralloc sa = {0};
  545.    static stralloc sa2 = {0};
  546.  
  547.    if (!stralloc_copy(&sa,&sender)) die_nomem();
  548.    if (!stralloc_0(&sa)) die_nomem();
  549.    if (!quote2(&sa2,sa.s)) die_nomem();
  550.  
  551.    puts("Return-Path: <");
  552.    put(sa2.s,sa2.len);
  553.    puts(">\n");
  554.   }
  555.  
  556.  /* could check at this point whether there are any recipients */
  557.  if (flagqueue)
  558.    if (qmail_open(&qqt) == -1) die_qqt();
  559.  
  560.  if (flagresent)
  561.   {
  562.    if (!htypeseen[H_R_DATE])
  563.     {
  564.      if (!newfield_datemake(starttime)) die_nomem();
  565.      puts("Resent-");
  566.      put(newfield_date.s,newfield_date.len);
  567.     }
  568.    if (!htypeseen[H_R_MESSAGEID])
  569.     {
  570.      if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem();
  571.      puts("Resent-");
  572.      put(newfield_msgid.s,newfield_msgid.len);
  573.     }
  574.    if (!htypeseen[H_R_FROM])
  575.     {
  576.      defaultfrommake();
  577.      puts("Resent-");
  578.      put(defaultfrom.s,defaultfrom.len);
  579.     }
  580.    if (!htypeseen[H_R_TO] && !htypeseen[H_R_CC])
  581.      puts("Resent-Cc: recipient list not shown: ;\n");
  582.   }
  583.  else
  584.   {
  585.    if (!htypeseen[H_DATE])
  586.     {
  587.      if (!newfield_datemake(starttime)) die_nomem();
  588.      put(newfield_date.s,newfield_date.len);
  589.     }
  590.    if (!htypeseen[H_MESSAGEID])
  591.     {
  592.      if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem();
  593.      put(newfield_msgid.s,newfield_msgid.len);
  594.     }
  595.    if (!htypeseen[H_FROM])
  596.     {
  597.      defaultfrommake();
  598.      put(defaultfrom.s,defaultfrom.len);
  599.     }
  600.    if (!htypeseen[H_TO] && !htypeseen[H_CC])
  601.      puts("Cc: recipient list not shown: ;\n");
  602.   }
  603.  
  604.  savedh_print();
  605. }
  606.  
  607. void getcontrols()
  608. {
  609.  static stralloc sa = {0};
  610.  char *x;
  611.  
  612.  if (control_init() == -1) die_read();
  613.  
  614.  if (control_rldef(&control_defaultdomain,"control/defaultdomain",1,"defaultdomain") != 1)
  615.    die_read();
  616.  x = env_get("QMAILDEFAULTDOMAIN");
  617.  if (x) if (!stralloc_copys(&control_defaultdomain,x)) die_nomem();
  618.  if (!stralloc_copys(&sa,".")) die_nomem();
  619.  if (!stralloc_cat(&sa,&control_defaultdomain)) die_nomem();
  620.  doordie(&sa,token822_parse(&defaultdomain,&sa,&defaultdomainbuf));
  621.  
  622.  if (control_rldef(&control_defaulthost,"control/defaulthost",1,"defaulthost") != 1)
  623.    die_read();
  624.  x = env_get("QMAILDEFAULTHOST");
  625.  if (x) if (!stralloc_copys(&control_defaulthost,x)) die_nomem();
  626.  if (!stralloc_copys(&sa,"@")) die_nomem();
  627.  if (!stralloc_cat(&sa,&control_defaulthost)) die_nomem();
  628.  doordie(&sa,token822_parse(&defaulthost,&sa,&defaulthostbuf));
  629.  
  630.  if (control_rldef(&control_plusdomain,"control/plusdomain",1,"plusdomain") != 1)
  631.    die_read();
  632.  x = env_get("QMAILPLUSDOMAIN");
  633.  if (x) if (!stralloc_copys(&control_plusdomain,x)) die_nomem();
  634.  if (!stralloc_copys(&sa,".")) die_nomem();
  635.  if (!stralloc_cat(&sa,&control_plusdomain)) die_nomem();
  636.  doordie(&sa,token822_parse(&plusdomain,&sa,&plusdomainbuf));
  637.  
  638.  if (control_rldef(&control_idhost,"control/idhost",1,"idhost") != 1)
  639.    die_read();
  640.  x = env_get("QMAILIDHOST");
  641.  if (x) if (!stralloc_copys(&control_idhost,x)) die_nomem();
  642. }
  643.  
  644. #define RECIP_DEFAULT 1
  645. #define RECIP_ARGS 2
  646. #define RECIP_HEADER 3
  647. #define RECIP_AH 4
  648.  
  649. void main(argc,argv)
  650. int argc;
  651. char **argv;
  652. {
  653.  int i;
  654.  int opt;
  655.  int recipstrategy;
  656.  struct passwd *pwent;
  657.  
  658.  sig_pipeignore();
  659.  
  660.  starttime = now();
  661.  
  662.  qmopts = env_get("QMAILINJECT");
  663.  if (qmopts)
  664.    while (*qmopts)
  665.      switch(*qmopts++)
  666.       {
  667.        case 'c': flagnamecomment = 1; break;
  668.        case 's': flagdeletesender = 1; break;
  669.        case 'f': flagdeletefrom = 1; break;
  670.        case 'i': flagdeletemessid = 1; break;
  671.        case 'r': flaghackrecip = 1; break;
  672.        case 'm': flaghackmess = 1; break;
  673.       }
  674.  
  675.  mailhost = env_get("QMAILHOST");
  676.  if (!mailhost) mailhost = env_get("MAILHOST");
  677.  mailrhost = env_get("QMAILSHOST");
  678.  if (!mailrhost) mailrhost = mailhost;
  679.  
  680.  mailuser = env_get("QMAILUSER");
  681.  if (!mailuser) mailuser = env_get("MAILUSER");
  682.  if (!mailuser) mailuser = env_get("USER");
  683.  if (!mailuser) mailuser = env_get("LOGNAME");
  684.  if (!mailuser && (pwent = getpwuid (getuid ()))) mailuser = pwent->pw_name;
  685.  if (!mailuser) mailuser = "anonymous";
  686.  mailusertokentype = TOKEN822_ATOM;
  687.  if (quote_need(mailuser,str_len(mailuser))) mailusertokentype = TOKEN822_QUOTE;
  688.  mailruser = env_get("QMAILSUSER");
  689.  if (!mailruser) mailruser = mailuser;
  690.  
  691.  for (i = 0;i < H_NUM;++i) htypeseen[i] = 0;
  692.  
  693.  recipstrategy = RECIP_DEFAULT;
  694.  flagqueue = 1;
  695.  
  696.  if (chdir(auto_qmail) == -1)
  697.    die_chdir();
  698.  getcontrols();
  699.  
  700.  if (!saa_readyplus(&hrlist,1)) die_nomem();
  701.  if (!saa_readyplus(&hrrlist,1)) die_nomem();
  702.  if (!saa_readyplus(&reciplist,1)) die_nomem();
  703.  
  704.  while ((opt = getopt(argc,argv,"aAhHnNf:")) != opteof)
  705.    switch(opt)
  706.     {
  707.      case 'a': recipstrategy = RECIP_ARGS; break;
  708.      case 'A': recipstrategy = RECIP_DEFAULT; break;
  709.      case 'h': recipstrategy = RECIP_HEADER; break;
  710.      case 'H': recipstrategy = RECIP_AH; break;
  711.      case 'n': flagqueue = 0; break;
  712.      case 'N': flagqueue = 1; break;
  713.      case 'f':
  714.        if (!quote2(&sender,optarg)) die_nomem();
  715.        doordie(&sender,token822_parse(&envs,&sender,&envsbuf));
  716.        token822_reverse(&envs);
  717.        rwgeneric(&envs);
  718.        token822_reverse(&envs);
  719.        if (token822_unquote(&sender,&envs) != 1) die_nomem();
  720.        break;
  721.      case '?':
  722.      default:
  723.        perm();
  724.     }
  725.  argc -= optind;
  726.  argv += optind;
  727.  
  728.  if (recipstrategy == RECIP_DEFAULT)
  729.    recipstrategy = (*argv ? RECIP_ARGS : RECIP_HEADER);
  730.  
  731.  if (recipstrategy != RECIP_HEADER)
  732.    while (*argv)
  733.      dorecip(*argv++);
  734.  
  735.  flagrh = (recipstrategy != RECIP_ARGS);
  736.  
  737.  if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1)
  738.    die_read();
  739.  exitnicely();
  740. }
  741.